<?php

namespace app\admin\traits;

use think\facade\Db;

/**
 * 百万级别的数据表导出逻辑 普通的EXCEL导出
 * 很容易导致内存溢出或者客户端假死。
 * 支持字符串转换 支持加密转换  支持时间戳转换
 */
trait Export {
    protected  $exportFields = [] ; //限定数据表的导出字段
    protected  $exportTitles = []; //导出的头标题 必须跟导出的对的上
    protected  $exportTranfer =[]; //需要转换的字段 类似status=1 需要转换成 是显示
    protected  $exportFileName = 'export.csv' ;//默认的导出表名，可以更改
    protected  $exportWhere =[] ;// TP里面的查询语句，如果是其他框架，改写对应查询条件
    protected  $exportOrderBy =['id'=>'desc'];
    protected  $exportTable = '';
    protected $exportAesDec = []; //需要解密的字符串
    protected $exportDateTime = [] ; //时间戳转换时间

    /**
     * 导出前对数据表进行初始化检测
     * @return void
     */
    private function  checkBeforExport() {
        if(!$this->exportTable)exit('未指定数据表');
        if(empty($this->exportFields)) exit('未指定导出字段');
        if(count($this->exportFields)!=count($this->exportTitles)) exit('导出字段和数据表字段对不上');

      }

    /**
     * 导出的核心方法
     * @return void
     */
    public  function exportBasic() {

      $this->checkBeforExport();

        ob_end_clean();
        header("Content-Type: application/force-download;");
        header("Content-Transfer-Encoding: binary");
        header("Content-type:text/csv;charset=utf-8");
        header("Content-Disposition: attachment; filename=" . $this->exportFileName);
        header("Expires: 0");
        header("Cache-control: private");
        header("Pragma: no-cache"); //不缓存页面

        //格式化导出
        $file = fopen('php://output', 'w');
        $bom = pack('CCC', 0xef, 0xbb, 0xbf);
        fwrite($file, $bom);
        fputcsv($file, $this->exportTitles);

        $page = 1 ; // 页面开始
        $page_size = 1000; //

        do{
            //数据显示
            $list =  \think\Db::table($this->exportTable)
                ->where($this->exportWhere)
                ->field(implode(',',$this->exportFields))
                ->limit($page_size)
                ->page($page)
                ->order($this->exportOrderBy)
                ->select();
            if(empty($list))  exit();
            $page++ ;
            foreach ($list  as   $val)  {
                $str = [];
                foreach ($this->exportFields as $field) {
                    //获取到需要转换，并且存在转换值
                    if(array_key_exists($field,$this->exportTranfer)&&isset($this->exportTranfer[$field][$val[$field]])) {
                        $str[]= "{$this->exportTranfer[$field][$val[$field]]}" . "\t";
                    }elseif (array_key_exists($field,$this->exportAesDec)) {
                        //需要解密的字段方法
                    } elseif (array_key_exists($field,$this->exportDateTime)) {
                        $str []= date('Y-m-d H:i:s',$val[$field]);
                    } else {
                        $str []= "{$val[$field]}" . "\t";
                    }
                }
                fputcsv($file, $str);
            }
        }while(count($list) == $page_size);
        exit();
    }

}